package com.i360day.invoker.codes.decoder;

import com.i360day.invoker.exception.InvalidContentTypeException;
import com.i360day.invoker.http.Response;
import com.i360day.invoker.properties.HttpInvokerProperties;
import com.i360day.invoker.support.RemoteInvocationResult;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.web.client.HttpMessageConverterExtractor;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;

public class SpringDecode implements Decoder {

    private ObjectFactory<HttpMessageConverters> messageConverters;
    private final HttpInvokerProperties.HttpInvokerResponseProperties responseProperties;

    public SpringDecode(ObjectFactory<HttpMessageConverters> messageConverters, HttpInvokerProperties httpInvokerProperties) {
        this.messageConverters = messageConverters;
        this.responseProperties = httpInvokerProperties.getResponse();
    }

    @Override
    public RemoteInvocationResult decode(Response response, Type type) throws IOException {
        try {
            if (!responseProperties.getContentType().equals(MediaType.valueOf(response.getContentType()))) {
                throw new InvalidContentTypeException(String.format("The response [%s] does not match the context [%s]", responseProperties.getContentType(), response.getContentType()));
            }
            //result input Stream
            HttpMessageConverterExtractor httpMessageConverterExtractor = new HttpMessageConverterExtractor(type, messageConverters.getObject().getConverters());
            //Result setn
            return new RemoteInvocationResult(httpMessageConverterExtractor.extractData(response.toClientHttpResponse()));
        } finally {
            response.close();
        }
    }

    public static class SimpleClientHttpResponse implements ClientHttpResponse {

        private InputStream inputStream;

        public SimpleClientHttpResponse(InputStream inputStream) {
            this.inputStream = inputStream;
        }

        @Override
        public HttpStatusCode getStatusCode() throws IOException {
            return inputStream == null || inputStream.available() <= -1 ? HttpStatusCode.valueOf(500) : HttpStatusCode.valueOf(200);
        }

        @Override
        public int getRawStatusCode() throws IOException {
            return inputStream == null || inputStream.available() <= -1 ? 500 : 200;
        }

        @Override
        public String getStatusText() throws IOException {
            return inputStream == null || inputStream.available() <= -1 ? "错误" : "正常";
        }

        @Override
        public void close() {
            try {
                inputStream.close();
            } catch (Exception ex) {
                //ignore ex
            }
        }

        @Override
        public InputStream getBody() throws IOException {
            return inputStream;
        }

        @Override
        public HttpHeaders getHeaders() {
            return HttpHeaders.EMPTY;
        }
    }
}
